<template>
  <CrudTable ref="tableRef" v-bind="tableProps" @selection-change="handleSelectionChange"
    @sort-change="handleSortChange" @row-click="handleRowClick" @row-dblclick="handleRowDblclick"
    @row-contextmenu="handleRowContextmenu" @cell-click="handleCellClick" @cell-dblclick="handleCellDblclick"
    @cell-contextmenu="handleCellContextmenu" @header-click="handleHeaderClick"
    @header-contextmenu="handleHeaderContextmenu">
    <!-- 动态生成列 -->
    <el-table-column v-for="column in processedColumns" :key="column.key" v-bind="column.props">
      <!-- 自定义列内容 -->
      <template v-if="column.type !== 'selection'" #default="{ row, column: col, $index }">
        <!-- 序号列 -->
        <template v-if="column.type === 'index'">
          {{ $index + 1 }}
        </template>

        <!-- 图片列 -->
        <template v-else-if="column.type === 'image'">
          <CrudImage :src="getColumnValue(row, column.prop) as string"
            :width="typeof column.imageConfig?.width === 'number' ? column.imageConfig.width : undefined"
            :height="typeof column.imageConfig?.height === 'number' ? column.imageConfig.height : undefined"
            :round="column.imageConfig?.round" :placeholder="column.imageConfig?.placeholder"
            :error-image="column.imageConfig?.errorImage" :preview="column.imageConfig?.preview"
            @error="(event) => emit('image-error', event, row, column)" />
        </template>

        <!-- 日期列 -->
        <template v-else-if="column.type === 'date'">
          <CrudDate :value="getColumnValue(row, column.prop) as string | number | Date" v-bind="column.dateConfig" />
        </template>

        <!-- 标签列 -->
        <template v-else-if="column.type === 'tag'">
          <CrudTag :value="getColumnValue(row, column.prop) as string | number | boolean" v-bind="column.tagConfig"
            @close="() => emit('tag-close', row, column)" @click="(event) => emit('tag-click', event, row, column)" />
        </template>

        <!-- 操作列 -->
        <template v-else-if="column.type === 'actions'">
          <div class="action-buttons">
            <CrudButton v-for="(action, actionIndex) in column.actions" :key="actionIndex"
              :type="getButtonType(action.type)" :size="action.size"
              :disabled="typeof action.disabled === 'function' ? action.disabled(row as TableRowData) : action.disabled"
              :link="action.link" :plain="action.plain" @click="handleActionClick(action, row, $index)">
              {{ action.label || action.text }}
            </CrudButton>
          </div>
        </template>

        <!-- 自定义渲染 -->
        <template v-else-if="column.render">
          <component :is="column.render" :row="row" :column="col" :index="$index"
            :value="getColumnValue(row, column.prop)" />
        </template>

        <!-- 插槽内容 -->
        <template v-else-if="column.slotName">
          <slot :name="column.slotName" :row="row" :column="col" :index="$index"
            :value="getColumnValue(row, column.prop)" />
        </template>

        <!-- 默认文本显示 -->
        <template v-else>
          {{ getColumnValue(row, column.prop) }}
        </template>
      </template>

      <!-- 表头插槽 -->
      <template v-if="column.headerSlotName" #header="headerScope">
        <slot :name="column.headerSlotName" v-bind="headerScope" />
      </template>
    </el-table-column>
  </CrudTable>
</template>

<script setup lang="ts">
import { ref, computed } from 'vue'
import { ElTableColumn } from 'element-plus'
import CrudTable from '../../crudstyle/CrudTable/index.vue'
import CrudButton from '../../crudstyle/CrudButton/index.vue'
import CrudImage from './CrudImage.vue'
import CrudDate from './CrudDate.vue'
import CrudTag from './CrudTag.vue'
import type {
  CrudDataTableProps,
  ColumnConfig,
  ActionButton,
  TableRowData,
  SortOrder
} from './types'

/**
 * 组件属性
 */
const props = withDefaults(defineProps<CrudDataTableProps>(), {
  data: () => [],
  columns: () => [],
  size: 'default',
  border: false,
  stripe: false,
  showHeader: true
})

/**
 * 事件定义
 */
const emit = defineEmits<{
  'selection-change': [selection: TableRowData[]]
  'sort-change': [sortInfo: { column: Record<string, unknown> | null; prop: string | null; order: SortOrder | null }]
  'row-click': [row: TableRowData, column: ColumnConfig, event: Event]
  'row-dblclick': [row: TableRowData, column: ColumnConfig, event: Event]
  'row-contextmenu': [row: TableRowData, column: ColumnConfig, event: Event]
  'cell-click': [row: TableRowData, column: ColumnConfig, cell: HTMLElement, event: Event]
  'cell-dblclick': [row: TableRowData, column: ColumnConfig, cell: HTMLElement, event: Event]
  'cell-contextmenu': [row: TableRowData, column: ColumnConfig, cell: HTMLElement, event: Event]
  'header-click': [column: ColumnConfig, event: Event]
  'header-contextmenu': [column: ColumnConfig, event: Event]
  'action-click': [action: ActionButton, row: TableRowData, index: number]
  'image-error': [event: Event, row: TableRowData, column: ColumnConfig]
  'tag-close': [row: TableRowData, column: ColumnConfig]
  'tag-click': [event: MouseEvent, row: TableRowData, column: ColumnConfig]
}>()

/**
 * 表格引用
 */
const tableRef = ref()

/**
 * 传递给 CrudTable 的属性
 */
const tableProps = computed(() => {
  const { columns: columnsIgnored, ...rest } = props
  return rest
})

/**
 * 处理后的列配置
 */
const processedColumns = computed(() => {
  return props.columns.map((column, index) => {
    const key = column.prop || `column-${index}`

    // 基础属性
    const baseProps: Record<string, unknown> = {
      prop: column.prop,
      label: column.label,
      width: column.width,
      minWidth: column.minWidth,
      fixed: column.fixed,
      align: column.align,
      headerAlign: column.headerAlign,
      sortable: column.sortable,
      showOverflowTooltip: column.showOverflowTooltip,
      className: column.className,
      labelClassName: column.labelClassName
    }

    // 特殊列类型的属性
    if (column.type === 'selection') {
      baseProps.type = 'selection'
      baseProps.selectable = column.selectable
    } else if (column.type === 'index') {
      baseProps.type = 'index'
      baseProps.index = column.index
    }

    return {
      key,
      type: column.type,
      prop: column.prop,
      props: baseProps,
      render: column.render,
      slotName: column.slotName,
      headerSlotName: column.headerSlotName,
      imageConfig: column.imageConfig,
      dateConfig: column.dateConfig,
      tagConfig: column.tagConfig,
      actions: column.actions
    }
  })
})

/**
 * 获取列值
 * @param row - 行数据
 * @param prop - 属性名
 */
const getColumnValue = (row: TableRowData, prop?: string): unknown => {
  if (!prop) return ''
  return prop.split('.').reduce((obj: Record<string, unknown>, key: string) => obj?.[key] as Record<string, unknown>, row as Record<string, unknown>) ?? ''
}

/**
 * 获取按钮类型
 * @param type - 按钮类型
 */
const getButtonType = (type?: string): 'add' | 'edit' | 'delete' | 'view' | 'search' | 'export' | 'import' | 'batch-delete' | 'primary' | 'success' | 'warning' | 'danger' | 'info' => {
  switch (type) {
    case 'delete':
      return 'delete'
    case 'add':
    case 'edit':
      return type
    case 'view':
      return 'view'
    case 'search':
      return 'search'
    case 'export':
      return 'export'
    case 'import':
      return 'import'
    case 'batch-delete':
      return 'batch-delete'
    case 'success':
      return 'success'
    case 'warning':
      return 'warning'
    case 'danger':
      return 'danger'
    case 'info':
      return 'info'
    default:
      return 'primary'
  }
}

/**
 * 处理选择变化
 * @param selection - 选中的行
 */
const handleSelectionChange = (selection: TableRowData[]) => {
  emit('selection-change', selection)
}

/**
 * 处理排序变化事件
 * @param sortInfo - 排序信息对象
 */
const handleSortChange = (sortInfo: { column: Record<string, unknown> | null; prop: string | null; order: SortOrder | null }) => {
  emit('sort-change', sortInfo)
}

/**
 * 处理行点击
 * @param row - 行数据
 * @param column - 列信息
 * @param event - 事件对象
 */
const handleRowClick = (row: TableRowData, column: ColumnConfig, event: Event) => {
  emit('row-click', row, column, event)
}

/**
 * 处理行双击
 * @param row - 行数据
 * @param column - 列信息
 * @param event - 事件对象
 */
const handleRowDblclick = (row: TableRowData, column: ColumnConfig, event: Event) => {
  emit('row-dblclick', row, column, event)
}

/**
 * 处理行右键
 * @param row - 行数据
 * @param column - 列信息
 * @param event - 事件对象
 */
const handleRowContextmenu = (row: TableRowData, column: ColumnConfig, event: Event) => {
  emit('row-contextmenu', row, column, event)
}

/**
 * 处理单元格点击
 * @param row - 行数据
 * @param column - 列信息
 * @param cell - 单元格元素
 * @param event - 事件对象
 */
const handleCellClick = (row: TableRowData, column: ColumnConfig, cell: HTMLElement, event: Event) => {
  emit('cell-click', row, column, cell, event)
}

/**
 * 处理单元格双击
 * @param row - 行数据
 * @param column - 列信息
 * @param cell - 单元格元素
 * @param event - 事件对象
 */
const handleCellDblclick = (row: TableRowData, column: ColumnConfig, cell: HTMLElement, event: Event) => {
  emit('cell-dblclick', row, column, cell, event)
}

/**
 * 处理单元格右键
 * @param row - 行数据
 * @param column - 列信息
 * @param cell - 单元格元素
 * @param event - 事件对象
 */
const handleCellContextmenu = (row: TableRowData, column: ColumnConfig, cell: HTMLElement, event: Event) => {
  emit('cell-contextmenu', row, column, cell, event)
}

/**
 * 处理表头点击
 * @param column - 列信息
 * @param event - 事件对象
 */
const handleHeaderClick = (column: ColumnConfig, event: Event) => {
  emit('header-click', column, event)
}

/**
 * 处理表头右键
 * @param column - 列信息
 * @param event - 事件对象
 */
const handleHeaderContextmenu = (column: ColumnConfig, event: Event) => {
  emit('header-contextmenu', column, event)
}

/**
 * 处理操作按钮点击
 * @param action - 操作配置
 * @param row - 行数据
 * @param index - 行索引
 */
const handleActionClick = (action: ActionButton, row: TableRowData, index: number) => {
  emit('action-click', action, row, index)
  action.handler?.(row, index)
}

/**
 * 暴露组件方法
 */
defineExpose({
  // 获取表格实例
  getTableRef: () => tableRef.value?.getTableRef()
})
</script>

<style lang="scss" scoped>
.action-buttons {
  display: flex;
  gap: 8px;
  align-items: center;

  .el-button {
    margin: 0;
  }
}
</style>
